/**
* TG_Coder: Dzlua
* Email: 505544956@qq.com
* Time: 2017/05/10
*/
#include "common.h"
#include <time.h>
#include <io.h>
#include <fstream>

std::string Common::lower(const std::string& src) {
    std::string str = src;
    for (size_t i = 0; i < str.length(); i++) {
		if (str[i] >= 'A' && str[i] <= 'Z') {
			str[i] += ('a' - 'A');
		}
	}
	return std::move(str);
}

bool Common::delete_file(const std::wstring & wstr_file_path)
{
	::DeleteFileW(wstr_file_path.c_str());
	return true;
}

bool Common::ReadTxtFileA(std::string m_filename, std::string& m_text)
{
	m_text = "";
	std::wstring m_tmp;
	bool m_retu = ReadTxtFileW(m_filename, m_tmp);
	if (m_retu)
		m_text = Common::Str_Conv::wstr2str(m_tmp);
	return m_retu;
}

bool Common::ReadTxtFileW(std::string m_filename, std::wstring & m_text)
{
	bool m_retu = FALSE;
	try{
		m_text = L"";
		HANDLE hFile = ::CreateFileA(m_filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		if (hFile != INVALID_HANDLE_VALUE) {
			DWORD dwSize = ::GetFileSize(hFile, NULL);
			if (dwSize > 0){
				DWORD dwRead = 0;
				BYTE* pByte = new BYTE[dwSize];
				::ReadFile(hFile, pByte, dwSize, &dwRead, NULL);
				::CloseHandle(hFile);
				if (LoadFromMem(pByte, dwSize, m_text)){
					m_retu = TRUE;
				}
				//
				if (pByte)
					delete[] pByte;
			}
		}
	}
	catch (...){

	}
	return m_retu;
}

bool Common::LoadFromMem(BYTE* pByte, DWORD dwSize, std::wstring& m_text)
{
	m_text = L"";
	try{
		LPWSTR m_pstrXML;
		if (dwSize >= 3 && pByte[0] == 0xEF && pByte[1] == 0xBB && pByte[2] == 0xBF)
		{//UTF8
			pByte += 3;
			dwSize -= 3;
			DWORD nWide = ::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pByte, dwSize, NULL, 0);
			m_pstrXML = static_cast<LPWSTR>(malloc((nWide + 1)*sizeof(WCHAR)));
			::MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide);
			m_pstrXML[nWide] = L'\0';
		}
		else if (dwSize >= 2 && ((pByte[0] == 0xFE && pByte[1] == 0xFF) || (pByte[0] == 0xFF && pByte[1] == 0xFE))){
			//unicode
			dwSize = dwSize / 2 - 1;
			if (pByte[0] == 0xFE && pByte[1] == 0xFF){
				pByte += 2;
				for (DWORD nSwap = 0; nSwap < dwSize; nSwap++){
					register CHAR nTemp = pByte[(nSwap << 1) + 0];
					pByte[(nSwap << 1) + 0] = pByte[(nSwap << 1) + 1];
					pByte[(nSwap << 1) + 1] = nTemp;
				}
			}
			else{
				pByte += 2;
			}
			m_pstrXML = static_cast<LPWSTR>(malloc((dwSize + 1)*sizeof(WCHAR)));
			::CopyMemory(m_pstrXML, pByte, dwSize * sizeof(WCHAR));
			m_pstrXML[dwSize] = L'\0';
			pByte -= 2;
		}
		else{
			//ASNI
			DWORD nWide = ::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pByte, dwSize, NULL, 0);
			m_pstrXML = static_cast<LPWSTR>(malloc((nWide + 1)*sizeof(WCHAR)));
			::MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pByte, dwSize, m_pstrXML, nWide);
			m_pstrXML[nWide] = L'\0';
		}
		m_text = m_pstrXML;
		return TRUE;
	}
	catch (...){
	}
	return FALSE;
}

bool Common::WriteTxtFileA(std::string m_filename, std::string m_text, int encoding)
{
	bool m_retu = FALSE;
	try{
		//��ɾ���ļ������ٴ��� 
		std::wstring m_filename2 = Common::Str_Conv::str2wstr(m_filename);
		delete_file(m_filename2);
		FILE* file_ptr = fopen((char*)m_filename.c_str(), "ab+");
		if (file_ptr)	{
			if (encoding == 0){
				//UTF8
				BYTE cbHeadFlag[] = { 0xEF, 0xBB, 0xBF };
				int len = sizeof(char);
				fwrite(cbHeadFlag, 1, 3, file_ptr);
				//GBKתUtf8
				m_text = Common::Str_Conv::GBK2UTF8(m_text);
				fwrite(m_text.c_str(), sizeof(char), m_text.length(), file_ptr);
			}
			else if (encoding == 1){
				//UNICODE
				BYTE cbHeadFlag[] = { 0xFF, 0xFE };
				int len = sizeof(TCHAR);
				//�����Ϊʲô ��������� 1 
				fwrite(cbHeadFlag, 2, 1, file_ptr);
				std::wstring m_str = Common::Str_Conv::str2wstr(m_text);
				fwrite(m_str.c_str(), 2, m_str.size(), file_ptr);
			}
			else{
				fwrite(m_text.c_str(), sizeof(char), m_text.length(), file_ptr);
			}
			fclose(file_ptr);
			m_retu = TRUE;
		}
	}
	catch (...){
	}
	return m_retu;
}

bool Common::WriteTxtFileW(std::string m_filename, std::wstring m_text, int encoding)
{
	return WriteTxtFileA(m_filename, Common::Str_Conv::wstr2str(m_text), encoding);
}

int Common::Str_Util::Replace_All(std::string& str, const std::string pattern, const std::string newpat)
{
	int count = 0;
	const size_t nsize = newpat.size();
	const size_t psize = pattern.size();

	for (size_t pos = str.find(pattern, 0);
		pos != std::string::npos;
		pos = str.find(pattern, pos + nsize))
	{
		str.replace(pos, psize, newpat);
		count++;
	}

	return count;
}

int Common::Str_Util::Replace_All(std::wstring& str, const std::wstring pattern, const std::wstring newpat)
{
	int count = 0;
	const size_t nsize = newpat.size();
	const size_t psize = pattern.size();

	for (size_t pos = str.find(pattern, 0);
		pos != std::string::npos;
		pos = str.find(pattern, pos + nsize))
	{
		str.replace(pos, psize, newpat);
		count++;
	}

	return count;
}

int Common::Str_Util::Splite_String2(std::string str, const std::string splite_str_sign, std::vector<std::string>& str_vector)
{
	try{
		if (str.length() == 0)
			return 0;
		str_vector.clear();
		for (size_t pos = str.find(splite_str_sign, 0);
			pos != std::string::npos;
			pos = str.find(splite_str_sign, 0))
		{
			str_vector.push_back(str.substr(0, pos));
			str = str.substr(pos + splite_str_sign.length());
		}
		str_vector.push_back(str.substr(0));
		return 1;
	}
	catch (...)
	{
		str_vector.clear();
		return 0;
	}
}

//---------------------//
std::string Common::Str_Conv::trim(std::string &text)
{
	if (!text.empty()){
		text.erase(0, text.find_first_not_of((" \n\r\t")));
		text.erase(text.find_last_not_of((" \n\r\t")) + 1);
	}
	return text;
}

std::wstring Common::Str_Conv::trimW(std::wstring &text)
{
	if (!text.empty()){
		text.erase(0, text.find_first_not_of(L" \n\r\t"));
		text.erase(text.find_last_not_of(L" \n\r\t") + 1);
	}
	return text;
}

std::wstring Common::Str_Conv::str2wstr(const std::string from, Char_Encode::encode_t char_code /*= char_encode::utf8*/)
{
	if (from.length() == 0)
		return L"";
	int buflen = MultiByteToWideChar(char_code, 0, from.c_str(), -1, NULL, 0) + 1;
	if (buflen == 0)
		return L"";
	wchar_t * buf = new wchar_t[buflen];
	std::wstring retn = L"";
	if (buf)
	{
		memset(buf, 0, buflen * 2);
		MultiByteToWideChar(char_code, 0, from.c_str(), -1, buf, buflen);
		retn = buf;
		delete[]buf;
	}
	return retn;
}

std::string Common::Str_Conv::wstr2str(const std::wstring from, Char_Encode::encode_t char_code /*= char_encode::utf8*/)
{
	if (from.length() == 0)
		return "";

	//�õ�ת������ҪBuf�ĳ���
	std::string retn = "";
	try{
		int buflen = WideCharToMultiByte(char_code, 0, from.c_str(), -1, NULL, 0, NULL, NULL) + 1;
		if (buflen == 0)
			return "";
		char * buf = new char[buflen];
		if (buf != NULL){
			memset(buf, 0, buflen);
			WideCharToMultiByte(char_code, 0, from.c_str(), -1, buf, buflen, NULL, NULL);
			retn = buf;
			delete[]buf;
		}
	}
	catch (...){

	}
	return retn;

}

std::string Common::Str_Conv::GBK2UTF8(std::string strGBK)
{
	if (strGBK.length() == 0)
		return "";

	std::string strOutUTF8 = "";
	wchar_t * str1;
	try{
		int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
		if (n == 0)
			return "";
		str1 = new WCHAR[n];
		if (NULL == str1)	{
			return "";
		}
		MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);
		n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);

		char * str2 = new char[n];
		if (str2 != NULL){
			WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
			strOutUTF8 = str2;
			delete[]str2;
			str2 = NULL;
		}

		if (str1 != NULL){
			delete[]str1;
			str1 = NULL;
		}
	}
	catch (...)
	{
		return "";
	}
	return strOutUTF8;
}

//----------------------//
bool Common::Arr_Util::Map_IsExistsA(std::map<std::string, std::string>& m_arr, std::string m_key)
{
	bool m_retu = false;
	std::map<std::string, std::string>::iterator itr = m_arr.find(m_key);
	if (itr != m_arr.end()){
		m_retu = true;
	}
	return m_retu;
}

bool Common::Arr_Util::Map_DelA(std::map<std::string, std::string>& m_arr, std::string m_key)
{
	bool m_retu = false;
	std::map<std::string, std::string>::iterator itr = m_arr.find(m_key);
	if (itr != m_arr.end()){
		m_arr.erase(itr);
		m_retu = true;
	}
	return m_retu;
}

bool Common::Arr_Util::Vector_Del(std::vector<std::string>& m_arr, std::string m_key)
{
	bool m_retu = false;
	std::vector<std::string>::iterator itr = find(m_arr.begin(), m_arr.end(), m_key);
	if (itr != m_arr.end()){
		m_arr.erase(itr);
		m_retu = true;
	}
	return m_retu;
}

bool Common::Arr_Util::Map_GetA(std::map<std::string, std::string>& m_arr, std::string m_key, std::string& m_value)
{
	bool m_retu = false;
	std::map<std::string, std::string>::iterator itr = m_arr.find(m_key);
	if (itr != m_arr.end()){
		m_value = itr->second;
		m_retu = true;
	}
	return m_retu;
}

//--------------------------//
#define DECODE_ERROR 0xffffffff 
static char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Common::Base64::pos(const char c)
{
	char *p;
	for (p = base64_chars; *p; p++)
	{
		if (*p == c)
		{
			return p - base64_chars;
		}
	}
	return -1;
}
unsigned int Common::Base64::token_decode(const char *token)
{
	int i;
	unsigned int val = 0;
	int marker = 0;
	if (strlen(token) < 4)
	{
		return DECODE_ERROR;
	}
	for (i = 0; i < 4; i++)
	{
		val *= 64;
		if (token[i] == '=')
		{
			marker++;
		}
		else
		{
			if (marker > 0)
			{
				return DECODE_ERROR;
			}
			else
			{
				val += pos(token[i]);
			}
		}
	}
	if (marker > 2)
	{
		return DECODE_ERROR;
	}
	return (marker << 24) | val;
}
int Common::Base64::base64_encode(const void *data, const int size, char **str)
{
	char *s, *p;
	int i;
	int c;
	const unsigned char *q;

	p = s = (char *)malloc(size * 4 / 3 + 4);
	if (p == NULL)
	{
		return -1;
	}
	q = (const unsigned char *)data;
	i = 0;
	for (i = 0; i < size;)
	{
		c = q[i++];
		c *= 256;
		if (i < size)
		{
			c += q[i];
		}
		i++;
		c *= 256;
		if (i < size)
		{
			c += q[i];
		}
		i++;
		p[0] = base64_chars[(c & 0x00fc0000) >> 18];
		p[1] = base64_chars[(c & 0x0003f000) >> 12];
		p[2] = base64_chars[(c & 0x00000fc0) >> 6];
		p[3] = base64_chars[(c & 0x0000003f) >> 0];
		if (i > size)
		{
			p[3] = '=';
		}
		if (i > size + 1)
		{
			p[2] = '=';
		}
		p += 4;
	}

	*p = 0;
	*str = s;
	return strlen(s);
}
int Common::Base64::base64_decode(const char *str, char *data)
{
	const char *p;
	unsigned char *q;

	q = (unsigned char *)data;
	for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4)
	{
		unsigned int val = token_decode(p);
		unsigned int marker = (val >> 24) & 0xff;
		if (val == DECODE_ERROR)
		{
			return -1;
		}
		*q++ = (val >> 16) & 0xff;
		if (marker < 2)
		{
			*q++ = (val >> 8) & 0xff;
		}
		if (marker < 1)
		{
			*q++ = val & 0xff;
		}
	}
	return q - (unsigned char *)data;
}

int  Common::Base64::Encode(const std::string &szInput, std::string &szOutput)
{
	int nRet = 0;
	int nLeng = 0;
	nLeng = (szInput.length() + 1)*sizeof(CHAR);
	char *pInput = new char[nLeng];
	ZeroMemory(pInput, nLeng);
	char *pOutput;
	//USES_CONVERSION; 
	//strcpy_s(pInput, nLeng, CT2A(szInput));
	strcpy_s(pInput, nLeng, szInput.c_str());
	nRet = base64_encode((void *)pInput, strlen(pInput), &pOutput);
	szOutput = pOutput;

	delete[]pInput;
	free(pOutput);
	return nRet;
}
int  Common::Base64::Decode(const std::string &szInput, std::string &szOutput)
{
	int nRet = 0;
	int nLeng = 0;
	nLeng = (szInput.length() + 1)*sizeof(CHAR);
	char *pInput = new char[nLeng];
	ZeroMemory(pInput, nLeng);
	char *pOutput = new char[nLeng];
	ZeroMemory(pOutput, nLeng);
	//USES_CONVERSION; 
	//strcpy_s(pInput, nLeng, CT2A(szInput));
	strcpy_s(pInput, nLeng, szInput.c_str());

	nRet = base64_decode(pInput, pOutput);
	szOutput = pOutput;
	delete[] pInput;
	delete[] pOutput;
	return nRet;
}

//--------------------//
